package edu.dayu.db;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import edu.dayu.config.CreateAndUpdateEntityHandler;
import edu.dayu.interceptor.ExecutorInterceptor;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


@Configuration
public class DynamicDataSourceConfig {

    // PRIMARY主库
//    @Bean
//    @Primary
//    @ConfigurationProperties("spring.datasource")
//    public DataSource primary() {
//        return DataSourceBuilder.create().build();
//    }


    /**
     * 因为如果 主动创建 DataSource 的 bean 会导致很多地方都要主动创建，
     * 所以选择使用 DataSourceProperties 来 new 一个主数据源出来。
     */
    @Bean
    public DynamicDataSource dataSource(DataSourceProperties dataSourceProperties){
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        dynamicDataSource.setDefaultTargetDataSource(dataSourceProperties.initializeDataSourceBuilder().build());
        String url = "jdbc:mysql://localhost:3306/test1?useSSL=false&useUnicode=true&allowMultiQueries=true&characterEncoding=utf-8";
        String username = "root";
        String pwd = "1212";
        String driverClass = "com.mysql.cj.jdbc.Driver";
        DruidDataSource dds  = setDataSource(url,pwd,username,driverClass);
        targetDataSources.put("test1",dds);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }

    public static DruidDataSource setDataSource(String url, String password, String username, String driverClass){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driverClass);
        //初始化大小，最小等待连接数量，最大等待连接数量，最大连接数
        druidDataSource.setInitialSize(5);
        druidDataSource.setMinIdle(1);
        druidDataSource.setMaxActive(32);
        //配置获取连接等待超时的时间
        druidDataSource.setMaxWait(60000l);
        druidDataSource.setUseGlobalDataSourceStat(true);

        druidDataSource.setValidationQuery("SELECT 1 ");
        //配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000l);
        //配置一个连接在池中最小生存的时间，单位是毫秒
        druidDataSource.setMinEvictableIdleTimeMillis(300000l);
        //下面三个参数的作用就是 申请连接时判断连接是否有效
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTestOnBorrow(true);
        druidDataSource.setTestOnReturn(false);
        // 打开PSCache，并且指定每个连接上PSCache的大小
        druidDataSource.setPoolPreparedStatements(true);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(200);
        return druidDataSource;
    }

    /**
     * 使用多数据源，必须自定义 SqlSessionFactory 因为我们需要自定义的 dataSource
     * 因为需要自定义，所以必须配置 xml 文件的对应方式，不然会报错
     * 然后因为我们需要使用 Mybatis-plus 的默认方法，所以需要配置 MybatisSqlSessionFactoryBean，不然无法进行绑定。
     * 因为 SqlSessionFactoryBean 是 mybatis 的，不是 mp 的
     */
//    @Bean
//    public MybatisSqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
//        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
//        sqlSessionFactoryBean.setDataSource(dataSource());
//        // 配置 xml 文件与接口的对应方式
//        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
//
//        // 保持 mybatis plus 的特性，如果只写前面就和 mybatis 一样了
//        MybatisConfiguration configuration = new MybatisConfiguration();
//        GlobalConfig globalConfig = new GlobalConfig();
//        globalConfig.setMetaObjectHandler(createAndUpdateEntityHandler);
//        configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
//        configuration.setJdbcTypeForNull(JdbcType.NULL);
//        // 注册
//        configuration.addInterceptor(new ExecutorInterceptor());
//        configuration.addInterceptor(mybatisPlusInterceptor());
//        sqlSessionFactoryBean.setConfiguration(configuration);
//        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
//        sqlSessionFactoryBean.setGlobalConfig(globalConfig);
//
//        return sqlSessionFactoryBean;
//    }


//    @Autowired
//    private CreateAndUpdateEntityHandler createAndUpdateEntityHandler;

    /**
     * 配置 mp 默认分页拦截器
     * @return
     */
//    @Bean
//    public MybatisPlusInterceptor mybatisPlusInterceptor(){
//        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//        mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor());
//        return mybatisPlusInterceptor;
//    }
//
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor(){
        PaginationInnerInterceptor interceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        interceptor.setMaxLimit(10L);
        return interceptor;
    }
}
